/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.uml_generator.model.impl;

import java.net.InetAddress;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

import com.genia.toolbox.basics.exception.BundledException;
import com.genia.toolbox.uml_generator.model.AbstractJavaObject;
import com.genia.toolbox.uml_generator.model.DataTypeModel;
import com.genia.toolbox.uml_generator.visitor.ModelVisitor;

/**
 * implementation of {@link DataTypeModel}.
 */
public class DataTypeModelImpl
    extends AbstractJavaObjectImpl
    implements DataTypeModel
{

  /**
   * returns the default value of the object.
   * 
   * @return the default value of the object
   */
  @Override
  public String getDefaultValue()
  {
    if (primitiveTypes.containsKey(getQualifiedName())) {
      return primitiveTypes.get(getQualifiedName()).initialValue;
    }
    return super.getDefaultValue();
  }

  /**
   * Informations needed to handle primitif types.
   */
  private static class PrimitifType
  {
    /**
     * the hibernate type to use.
     */
    private final DataTypeModel hibernateType;

    /**
     * the default initial value.
     */
    private final String initialValue;



    /**
     * constructor.
     * 
     * @param hibernateType
     *          the hibernate type associated to the type
     * @param initialValue
     *          the initial value for the type
     */
    public PrimitifType(Class<?> hibernateType, String initialValue)
    {
      this.hibernateType = new ExistentDataTypeModel(hibernateType, "");
      this.initialValue = initialValue;
    }
  }

  /**
   * {@link Map} containing all the primitive types.
   */
  private static Map<String, PrimitifType> primitiveTypes = new TreeMap<String, PrimitifType>();

  static {
    primitiveTypes.put("boolean", new PrimitifType(Boolean.class, "false"));
    primitiveTypes.put("byte", new PrimitifType(Byte.class, "0"));
    primitiveTypes.put("char", new PrimitifType(Character.class, "0"));
    primitiveTypes.put("short", new PrimitifType(Short.class, "0"));
    primitiveTypes.put("int", new PrimitifType(Integer.class, "0"));
    primitiveTypes.put("long", new PrimitifType(Long.class, "0"));
    primitiveTypes.put("float", new PrimitifType(Float.class, "0"));
    primitiveTypes.put("double", new PrimitifType(Double.class, "0"));
  }



  /**
   * return the object type that represents this type. For non primitive type,
   * it is always itself, for primitive type it is the correct wrapper.
   * 
   * @return the object type that represents this type
   */
  @Override
  public AbstractJavaObject getObject()
  {
    String type = getQualifiedName();
    if (primitiveTypes.containsKey(type)) {
      return primitiveTypes.get(type).hibernateType;
    }
    return super.getObject();
  }

  /**
   * url of type String. Because String are in the java.lang package, only the
   * simpleName is used.
   */
  private static final String URL_STRING = String.class.getSimpleName();

  /**
   * url of type String. Because String are in the java.lang package, only the
   * simpleName is used.
   */
  private static final String URL_TEXT = "Text";

  /**
   * class name of type {@link InetAddress}.
   */
  private static final String INET_ADDRESS_CLASS_NAME = InetAddress.class.getCanonicalName();

  /**
   * qualified name of type {@link Locale}.
   */
  private static final String LOCALE_CLASS_NAME = Locale.class.getCanonicalName();

  /**
   * qualified name of type {@link Date}.
   */
  private static final String DATE_CLASS_NAME = Date.class.getCanonicalName();

  /**
   * simple name of type {@link Date}.
   */
  private static final String DATE_SIMPLE_NAME = Date.class.getSimpleName();

  /**
   * qualified name of type {@link Date}.
   */
  private static final String TIME_CLASS_NAME = "java.util.Time";

  /**
   * qualified name of type {@link Date}.
   */
  private static final String DATE_TIME_CLASS_NAME = "java.util.DateTime";

  /**
   * hibernate type for {@link Locale}.
   */
  private static final String LOCALE_HIBERNATE_TYPE = "locale";

  /**
   * hibernate type for {@link Date}.
   */
  private static final String DATE_HIBERNATE_TYPE = "date";

  /**
   * hibernate type for {@link Date}.
   */
  private static final String TIME_HIBERNATE_TYPE = "time";

  /**
   * hibernate type for {@link Date}.
   */
  private static final String DATE_TIME_HIBERNATE_TYPE = "timestamp";

  /**
   * url for the type hibernate escaped string.
   */
  private static final String URL_HIBERNATE_ESCAPED_STRING = "com.genia.toolbox.persistence.hibernate.mapping.type.HibernateEscapedString";

  /**
   * url for the type hibernate escaped text.
   */
  private static final String URL_HIBERNATE_ESCAPED_TEXT = "com.genia.toolbox.persistence.hibernate.mapping.type.HibernateEscapedText";

  /**
   * class name of type
   * com.genia.toolbox.persistence.hibernate.mapping.type.InetAddressHibernateType.
   */
  private static final String INET_ADDRESS_HIBERNATE_TYPE_CLASS_NAME = "com.genia.toolbox.persistence.hibernate.mapping.type.InetAddressHibernateType";

  /**
   * the qualified name to use in the hibernate mapping file.
   */
  private String hibernateQualifiedName = null;



  /**
   * returns the qualified name to use in the hibernate mapping file.
   * 
   * @return the qualified name to use in the hibernate mapping file
   * @see com.genia.toolbox.uml_generator.model.AbstractJavaObject#getHibernateQualifiedName()
   */
  @Override
  public String getHibernateQualifiedName()
  {
    return hibernateQualifiedName;
  }



  /**
   * setter for the name property.
   * 
   * @param name
   *          the name to set
   * @see com.genia.toolbox.uml_generator.model.AbstractObject#setName(String)
   */
  @Override
  public void setName(String name)
  {
    super.setName(name);
    String type = getQualifiedName();
    if (type.contains("<")) {
      type = type.split("\\<|\\>")[0];
    }
    if (primitiveTypes.containsKey(type)) {
      hibernateQualifiedName = primitiveTypes.get(type).hibernateType.getHibernateQualifiedName();
      return;
    }
    if (type.equals(URL_TEXT)) {
      super.setName(URL_STRING);
      hibernateQualifiedName = URL_HIBERNATE_ESCAPED_TEXT;
      return;
    }
    if (type.equals(URL_STRING)) {
      hibernateQualifiedName = URL_HIBERNATE_ESCAPED_STRING;
      return;
    }
    if (type.equals(LOCALE_CLASS_NAME)) {
      hibernateQualifiedName = LOCALE_HIBERNATE_TYPE;
      return;
    }
    if (type.equals(DATE_CLASS_NAME)) {
      hibernateQualifiedName = DATE_HIBERNATE_TYPE;
      return;
    }
    if (type.equals(TIME_CLASS_NAME)) {
      super.setName(DATE_SIMPLE_NAME);
      hibernateQualifiedName = TIME_HIBERNATE_TYPE;
      return;
    }
    if (type.equals(DATE_TIME_CLASS_NAME)) {
      super.setName(DATE_SIMPLE_NAME);
      hibernateQualifiedName = DATE_TIME_HIBERNATE_TYPE;
      return;
    }
    if (type.equals(INET_ADDRESS_CLASS_NAME)) {
      hibernateQualifiedName = INET_ADDRESS_HIBERNATE_TYPE_CLASS_NAME;
      setLength(16);
      return;
    }
    if (getPackageName().equals("")) {
      hibernateQualifiedName = "java.lang." + type;
      return;
    }
    hibernateQualifiedName = type;
  }



  /**
   * the actual visitor method.
   * 
   * @param modelVisitor
   *          the visitor to use
   * @throws BundledException
   *           when an error occurred
   * @see com.genia.toolbox.uml_generator.visitor.Visitable#visit(com.genia.toolbox.uml_generator.visitor.ModelVisitor)
   */
  public void visit(ModelVisitor modelVisitor)
      throws BundledException
  {
    modelVisitor.visitDataTypeModel(this);

  }

}
